<?php
namespace Managers;
use Lib\ResLoader,
Lib\Model\DoctrineManager,
Doctrine\ORM\Query\Expr\Func;

/**
 * Base class for models
 *
 * @since 23 июня 2010
 * @author diotheos
 */
class BaseManager extends DoctrineManager
{

    protected $_defaultEntityName;

    protected static $_entityNamspace = 'Automoto';

    protected $__table;

    private $__cache;

    /**
     * Тег для всех маленьких таблиц
     * @todo Зробити очистку кеша по даному тегу десь в адмінці
     * @var unknown_type
     */
    public $_cache_tags = array('small_tables');

    public $_cache_time = 86400; // 60 * 60 * 24

    private $_cache_flag = 1;

    /**
     *
     * Устанавливает ключем строки значение ключевого поля в строке
     * Необходимо при роботе с кешом, чтобы напрямую обращатся по ИДшке к елементу
     * @param array $array
     * @param string $key
     * @return array $asoc_array
     */
    public function toKey_Row($array, $key)
    {
        if (!sizeof($array)) return $array;
        $asoc_array = array();
        foreach ($array as $item) {
            $asoc_array[$item[$key]] = $item;
        }
        return $asoc_array;
    }


    /**
     * @author megadevel
     */
    public function getCount()
    {
        $query = $this->_em->createQuery("SELECT COUNT(u.id) FROM " . $this->__table . " u");
        return $query->getSingleScalarResult();
    }

    /**
     * @author megadevel
     * @since 24 нояб. 2010
     */
    public function getById($id)
    {
        $result = $this->_em->createQueryBuilder()
                ->select('m')
                ->from($this->__table, 'm')
                ->where('m.id = :id')->setParameter('id', $id)
                ->getQuery()
                ->getArrayResult();

        return count($result) ? $result[0] : false;
    }

    /**
     * Get info by name
     * @param string $name
     */
    public function getByLocale($name)
    {
        $result = $this->_em->createQueryBuilder()
                ->select('m')
                ->from($this->__table, 'm')
                ->where('m.name = :name')->setParameter('name', $name)
                ->getQuery()
                ->getArrayResult();

        return isset($result[0]) ? $result[0] : false;
    }


    /**
     * @author megadevel
     * @since Jan 18, 2011
     * @param
     * @return
     */
    public function updateFromArray($id, array $params)
    {
        $entity = $this->_em->find($this->__table, $id);
        if (!$entity) return false;
        $entity = $this->setFromArray($params, $entity);
        if (!$entity) return false;

        $this->_em->persist($entity);
        $this->_em->flush();
        return $entity;
    }


    /**
     * @author megadevel
     * @since Jan 18, 2011
     * @param
     * @return
     */
    public function insertFromArray(array $params)
    {
        $entity = $this->setFromArray($params);
        if (!$entity) return false;

        $this->_em->persist($entity);
        $this->_em->flush();
        return $entity->getId();
    }

    /**
     * @author megadevel
     * @since Jan 18, 2011
     * @param
     * @return
     */
    public function delete($id)
    {
        $entity = $this->_em->find($this->__table, $id);
        if ($entity) {
            $this->_em->remove($entity);
            $this->_em->flush();
            return true;
        }
        return false;
    }


    /**
     * @author megadevel
     * @since Jan 17, 2011
     * @param
     * @return
     */
    public function setFromArray(array $params, $entity = null)
    {
        $reflection = new \ReflectionClass($this->__table);
        $changes_flag = false;

        if (!$entity or !is_object($entity))
            $entity = new $this->__table;
        $property = array_keys($reflection->getDefaultProperties());

        foreach ($property as $item) {
            //check is primary in DocComment
            if (strpos($reflection->getProperty($item)->getDocComment(), '@Id') > 0) continue;
            if (strpos($comment = $reflection->getProperty($item)->getDocComment(), 'targetEntity=') > 0) {
                preg_match_all('#targetEntity="(.*?)"#', $comment, $searched);
                if (isset($searched[1][0]) && strlen($searched[1][0])) {
                    $itemRefer = $this->_em->getReference(self::$_entityNamspace . '\\' . $searched[1][0], $params[$item]);
                }
            }

            if (isset($params[$item]) && $reflection->hasMethod($method = 'set' . ucfirst($item))) {
                $entity->$method(isset($itemRefer) ? $itemRefer : $params[$item]);
                $changes_flag = true;
            }
            unset($itemRefer);
        }
        if ($changes_flag) return $entity;
        else return false;
    }


    /**
     * Генерируем имя ключа для кеша в зависимости от сущности
     * @param string $table
     */
    public function getCacheName($table = '', $prefix = '')
    {
        return 'My_table' . $prefix . str_replace("\\", '___', $table);
    }

    /**
     * Робота з кешом для простих таблиць (don't use MySQL)
     * Бере з регистра, якщо нема - ломиться в редіс і тільки потом в базу
     * @param string $table
     * @param integer $id
     * @fixme Зробити рефактор кода. Можливі потенційні проблеми
     * @return array
     */
    public function getFromCacheArray($table, $id = null)
    {
        $in_register = false;
        if (\Zend_Registry::isRegistered($cname = $this->getCacheName($table))) {
            $result = \Zend_Registry::get($cname);
            $in_register = true;
        }
        else {
            $result = $this->_getCacheManager()->load($cname);
        }

        //проверка есть ли таблица в кеше
        if (!$result) {
            $result = $this->getItems($table, null, true);
            if (!count($result)) return false;

            $result = $this->toKey_Row($result, 'id');
            $this->_getCacheManager()->save($result, $cname, $this->_cache_tags, $this->_cache_time);
        }

        if (!$in_register) \Zend_Registry::set($cname, $result);

        if (!$id)
            return $result;
        else {
            if (is_array($id)) {
                $tmp_result = array();
                foreach ($id as $item) $tmp_result[] = $result[$item];
                return $tmp_result;
            }
            else {
                if (isset($result[$id]))
                    return $result[$id];
                return null;
            }
        }
    }

    /**
     * @todo Рефактор + в конфиги вынести настройки
     * @return \Zend_Cache_Core
     */
    public function _getCacheManager()
    {
        return \Lib\ResLoader::getResource('redis');
    }

    /**
     *
     * Простая робота с SQL строкой
     * @param string $qs
     * @param integer $memcache_time
     * @param string $memcahe_name
     */
    public function getArray($qs, $memcache_time = 0, $memcahe_name = '')
    {
        if ($memcache_time) {
            $data = $this->_getCacheManager()->load(self::getMemcacheName($qs, $memcahe_name));
            if ($data !== false) return $data;
        }
        //if no data
        $data = $this->getEntityManager()->getConnection()->executeQuery($qs)->fetchAll();
        if ($memcache_time) {
            $this->_getCacheManager()->save($data, self::getMemcacheName($qs, $memcahe_name), array('sql'));
        }
        return $data;
    }

    /**
     * Make memcache name
     * @param string $qs
     * @param string $name
     */
    protected static function getMemcacheName($qs, $name = '')
    {
        if ($name != '') $key = $name;
        else $key = 'My_' . crc32($qs);

        return $key;
    }

}